// text.cpp - GUIText object

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>

#include <string>

extern "C" {
#include "../common.h"
#include "../minuitwrp/minui.h"
#include "../recovery_ui.h"
}

#include "rapidxml.hpp"
#include "objects.hpp"

GUIText::GUIText(xml_node<>* node)
    : Conditional(node)
{
    xml_attribute<>* attr;
    xml_node<>* child;

    mFont = NULL;
    mIsStatic = 1;
    mVarChanged = 0;
    mFontHeight = 0;
	maxWidth = 0;
	charSkip = 0;

    if (!node)      return;

    // Initialize color to solid black
    memset(&mColor, 0, sizeof(COLOR));
    mColor.alpha = 255;

    attr = node->first_attribute("color");
    if (attr)
    {
        std::string color = attr->value();
        ConvertStrToColor(color, &mColor);
    }

    // Load the font, and possibly override the color
    child = node->first_node("font");
    if (child)
    {
        attr = child->first_attribute("resource");
        if (attr)
            mFont = PageManager::FindResource(attr->value());

        attr = child->first_attribute("color");
        if (attr)
        {
            std::string color = attr->value();
            ConvertStrToColor(color, &mColor);
        }
    }

    // Load the placement
    LoadPlacement(node->first_node("placement"), &mRenderX, &mRenderY, &mRenderW, &mRenderH, &mPlacement);

    child = node->first_node("text");
    if (child)  mText = child->value();

    // Simple way to check for static state
    mLastValue = parseText();
    if (mLastValue != mText)   mIsStatic = 0;

    gr_getFontDetails(mFont ? mFont->GetResource() : NULL, (unsigned*) &mFontHeight, NULL);
    return;
}

int GUIText::Render(void)
{
    if (!isConditionTrue())     return 0;

    void* fontResource = NULL;
	string displayValue;

    if (mFont)  fontResource = mFont->GetResource();

    mLastValue = parseText();
	displayValue = mLastValue;

	if (charSkip)
		displayValue.erase(0, charSkip);

    mVarChanged = 0;

    int x = mRenderX, y = mRenderY;
    int width = gr_measureEx(displayValue.c_str(), fontResource);

    if (mPlacement != TOP_LEFT && mPlacement != BOTTOM_LEFT)
    {
        if (mPlacement == CENTER || mPlacement == CENTER_X_ONLY)
            x -= (width / 2);
        else
            x -= width;
    }
    if (mPlacement != TOP_LEFT && mPlacement != TOP_RIGHT)
    {
        if (mPlacement == CENTER)
            y -= (mFontHeight / 2);
        else if (mPlacement == BOTTOM_LEFT || mPlacement == BOTTOM_RIGHT)
            y -= mFontHeight;
    }

    gr_color(mColor.red, mColor.green, mColor.blue, mColor.alpha);

	if (maxWidth)
		gr_textExW(x, y, displayValue.c_str(), fontResource, maxWidth + x);
	else
		gr_textEx(x, y, displayValue.c_str(), fontResource);
    return 0;
}

int GUIText::Update(void)
{
    if (!isConditionTrue())     return 0;

    static int updateCounter = 3;

    // This hack just makes sure we update at least once a minute for things like clock and battery
    if (updateCounter)  updateCounter--;
    else
    {
        mVarChanged = 1;
        updateCounter = 3;
    }

    if (mIsStatic || !mVarChanged)      return 0;

    std::string newValue = parseText();
    if (mLastValue == newValue)         return 0;
    return 2;
}

int GUIText::GetCurrentBounds(int& w, int& h)
{
    void* fontResource = NULL;

    if (mFont)  fontResource = mFont->GetResource();

    h = mFontHeight;
    w = gr_measureEx(mLastValue.c_str(), fontResource);
    return 0;
}

std::string GUIText::parseText(void)
{
    static int counter = 0;
    std::string str = mText;
    size_t pos = 0;
    size_t next = 0, end = 0;

    while (1)
    {
        next = str.find('%', pos);
        if (next == std::string::npos)      return str;
        end = str.find('%', next + 1);
        if (end == std::string::npos)       return str;

        // We have a block of data
        std::string var = str.substr(next + 1, (end - next) - 1);
        str.erase(next, (end - next) + 1);

        if (next + 1 == end)
        {
            str.insert(next, 1, '%');
        }
        else
        {
            std::string value;
            if (DataManager::GetValue(var, value) == 0)
                str.insert(next, value);
        }

        pos = next + 1;
    }
}

int GUIText::NotifyVarChange(std::string varName, std::string value)
{
    mVarChanged = 1;
    return 0;
}

int GUIText::SetMaxWidth(unsigned width)
{
	maxWidth = width;
	mVarChanged = 1;
	return 0;
}

int GUIText::SkipCharCount(unsigned skip)
{
	charSkip = skip;
	mVarChanged = 1;
	return 0;
}
